package com.vision.sales.cm.db.data;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import net.sf.gilead.pojo.gwt.LightEntity;

import com.vision.core.cm.data.IHasSystemTime;
import com.vision.core.cm.db.data.Company;

/**
 * Represents a payment made in advance by a {@link Customer}. An {@link AdvancePayment}
 * can be applied to multiple {@link SalesInvoice}s in partial amounts via the
 * {@link AppliedAdvancePayment} class.
 * 
 * @author Mark
 *
 */
@Entity
@Table(name = AdvancePayment.TABLE)
public class AdvancePayment extends LightEntity implements Serializable, IHasSystemTime {
	
	public static interface FieldSpecs {
		int AP_NO_MAX = 20;
		int REMARKS_MAX = 300;
	}

	private static final long serialVersionUID = 5586067613565544061L;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public static final String TABLE = "advance_payment";
	
	public static final String COL_ID = "id";
	public static final String COL_COMPANY_ID = "company_id";
	public static final String COL_NO = "advance_payment_no";
	public static final String COL_CUSTOMER_ID = "customer_id";
	public static final String COL_DATE = "date";
	public static final String COL_AMOUNT = "amount";
	public static final String COL_APPLIED_AMOUNT = "applied_amount";
	public static final String COL_BALANCE = "balance";
	public static final String COL_REMARKS = "remarks";
	
	public static final String COL_SYS_CREATED = "sys_created";
	public static final String COL_SYS_LAST_MOD = "sys_last_mod";
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "sadvance_payment")
	@SequenceGenerator(name = "sadvance_payment", sequenceName = "advance_payment_seq")
	@Column(name = COL_ID)
	private Long id;
	
	/**
	 * The {@link Company}.
	 */
	@ManyToOne
	@JoinColumn(name = COL_COMPANY_ID, nullable = false)
	private Company company;
	
	/**
	 * The {@link AdvancePayment}'s number.
	 */
	@Column(name = COL_NO, nullable = false, unique = true, length = FieldSpecs.AP_NO_MAX)
	private String advancePaymentNo;
	
	/**
	 * The {@link Customer}.
	 */
	@ManyToOne
	@JoinColumn(name = COL_CUSTOMER_ID, nullable = false)
	private Customer customer;
	
	/**
	 * The {@link AdvancePayment}'s date.
	 */
	@Column(name = COL_DATE, nullable = false)
	@Temporal(TemporalType.DATE)
	private Date date;
	
	/**
	 * The amount to be applied.
	 */
	@Column(name = COL_AMOUNT, nullable = false)
	private double amount;
	
	@Column(name = COL_APPLIED_AMOUNT, nullable = false)
	private double appliedAmount;
	
	@Column(name = COL_BALANCE, nullable = false)
	private double balance;
	
	/**
	 * User remarks.
	 */
	@Column(name = COL_REMARKS, nullable = true, length = FieldSpecs.REMARKS_MAX)
	private String remarks;
	
	@OneToMany(mappedBy = "advancePayment", fetch = FetchType.LAZY) // TODO Cascade
	private Set<AppliedAdvancePayment> appliedAdvancePayments = new HashSet<AppliedAdvancePayment>();
	
	// For internal use %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * The server {@link Timestamp} this object was created.
	 */
	@Column(name = COL_SYS_CREATED, nullable = false)
	private Timestamp sysCreated;
	
	/**
	 * The server {@link Timestamp} this object was last modified.
	 */
	@Column(name = COL_SYS_LAST_MOD, nullable = false)
	private Timestamp sysLastModified;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	public AdvancePayment() { }
	
	public AdvancePayment(Date date) {
		this.date = date;
	}
	
	@Override
	public boolean equals(Object object) {
		if (object instanceof AdvancePayment) {
			AdvancePayment o = (AdvancePayment) object;
			return id.equals(o.id);
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return id == null ? super.hashCode() : id.hashCode();
	}
	
	@Override
	public String toString() {
		return id + ": " + advancePaymentNo + "(" + date + ")";
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	public Company getCompany() {
		return company;
	}

	public void setCompany(Company company) {
		this.company = company;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getAdvancePaymentNo() {
		return advancePaymentNo;
	}

	public void setAdvancePaymentNo(String advancePaymentNo) {
		this.advancePaymentNo = advancePaymentNo;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public double getAmount() {
		return amount;
	}

	public void setAmount(double amount) {
		this.amount = amount;
	}

	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public double getAppliedAmount() {
		return appliedAmount;
	}

	public void setAppliedAmount(double appliedAmount) {
		this.appliedAmount = appliedAmount;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	public String getRemarks() {
		return remarks;
	}

	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}
	
	public Set<AppliedAdvancePayment> getAppliedAdvancePayments() {
		return appliedAdvancePayments;
	}
	
	public void setAppliedAdvancePayments(Set<AppliedAdvancePayment> appliedAdvancePayments) {
		this.appliedAdvancePayments = appliedAdvancePayments;
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	public Timestamp getSysCreated() {
		return sysCreated;
	}

	public void setSysCreated(Timestamp sysCreated) {
		this.sysCreated = sysCreated;
	}

	public Timestamp getSysLastModified() {
		return sysLastModified;
	}

	public void setSysLastModified(Timestamp sysLastModified) {
		this.sysLastModified = sysLastModified;
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public String getDisplayText() {
		return getDate() + "    " + getAdvancePaymentNo() + "    " + getAmount();
	}
	
	public void setDisplayText(String text) {
		// Do nothing
	}

}
